/**
 * Caliga JavaScript Library v0.0.6
 * http://www.caliga.eu/
 *
 * Creation Date: Thi Aug 31 18:10:42 2011
 * Author : Bouhours Julien
 */
 
(function(){
	
	/**
	 * @namespace
	 * @name Clg
	 * @description Holds all classes and functionalities of Caliga.  
	 */
	var global = this;

	if (typeof Clg === 'undefined') {
    	global.Clg = {};
	}

	/**
	 *	@namespace Holds tools functionality.
	 */
	Clg.Utils = {
		
		/**
		 *	@function
		 *	@description Test if the value is a variable number.
		 *	@param n value that will be tested.
		 *	@returns {Boolean} True when the value is a type number.
		 */
		isNumber : function(n) {
			return !isNaN(parseFloat(n)) && isFinite(n);
		},
		
		/**
		 *	@function
		 *	@description Allows inheritance between objects.
		 *	@param dstObj The child object will inherit the attributes and functions of parents.
		 *	@param srcObj Table of parents with whom the object "dstObj" will inherit their attributes and functions.
		 *	@param conf Configuration object from the object "dstObj" containing the attributes and function overriding that of the latter by their parents.
		 * 	@returns {void} 
		 */
		extend : function(dstObj,srcObj,conf){
			if (srcObj == "undefined")
				return false;
			for (var i = 0;i < srcObj.length;i++) {
				var obj = srcObj[i];
				obj.call(dstObj,conf);
				if ( typeof dstObj.initialized == "undefined" ) {
					for (var element in obj.prototype ) {
						dstObj.prototype[element] = obj.prototype[element];
					}
					dstObj.initialized = true;
				}
			}
			return true;
		}
	};
	
	/**
	 *	@namespace Holds motion functionality.
	 */
	Clg.Motion = {
		
	};
	
	/**
	 *	@class Dot
	 * 	@description An object representing a point on the canvas. This object is expressed in Cartesian coordinates, x to the abscissa and y to the ordinate.
	 *	@param conf Configuration object with two objects of type number called x and y.
	 */
	Clg.Dot = function(conf){
		this.x = 0;
		this.y = 0;
		
		/**
		 *	@function
		 *	@description Returns the component of the abscissa of the point
		 *	@returns {number} 
		 */
		this.getX = function(){
			return this.x;	
		};
		
		/**
		 *	@function
		 *	@description Returns the component of the ordinate of the point
		 *	@returns {number} 
		 */
		this.getY = function(){
			return this.y;	
		};
		
		/**
		 *	@function
		 *	@description Returns the component of the ordinate and the abscissa of the point
		 *	@returns {objet} 
		 */
		this.getXY = function(){
			return {x:this.getX(),y:this.getY()};
		};
		
		/**
		 *	@function
		 *	@description Set the component of the abscissa of the point
		 *	@param {number} newX New value of the component of the abscissa of the point
		 */
		this.setX = function(newX){
			if (Clg.Utils.isNumber(newX))
				this.x = newX;	
		};
		
		/**
		 *	@function
		 *	@description Set the component of the ordinate of the point
		 *	@param {number} newY New value of the component of the ordinate of the point
		 */
		this.setY = function(newY){
			if (Clg.Utils.isNumber(newY))
				this.y = newY;
		};
		
		/**
		 *	@function
		 *	@param {object} newXY New value of the component of the abscissa and the ordinate of the point
		 *	@description Set the component of the abscissa and the ordinate of the point 
		 */
		this.setXY = function(newXY){
			this.constructor(newXY);
		};
		
		/**
		 *	@constructor
		 *	@private
		 */ 
		this.constructor = function(conf){
			if (!conf)
				return;
			if (conf.x != null && Clg.Utils.isNumber(conf.x))
				this.setX(conf.x);
			if (conf.y != null && Clg.Utils.isNumber(conf.y))
				this.setY(conf.y);
			return this;
		};
		
		return this.constructor(conf);
	};
	
	/**
	 *	@class Shape
	 */
	Clg.Shape = function(conf) {
		this.dots = new Array();
		this.pos = new Clg.Dot();
		this.drawType = "fill"; // or stroke
		
		this.getPos = function(){
			return this.pos;
		};
		
		this.getDots = function(){
			return this.dots;
		};
		
		this.getDrawType = function(){
			return this.drawType;	
		};
		
		this.setPos = function(newPos){
			if(newPos)
				this.pos.setXY(newPos);
		};
		
		this.setDrawType = function(newDrawType){
			if(newDrawType)
				this.drawType = newDrawType;
		};
		
		this.draw = function(ctx){
			ctx.beginPath();
			ctx.moveTo(this.getPos().getX(),this.getPos().getY());
			var tmp = this.getDots();
			for(var i=0;i<tmp.length;i++){
				ctx.lineTo(tmp[i].getX(),tmp[i].getY());
			}
			ctx.closePath();
			if (this.getDrawType() == "fill")
				ctx.fill();
			else 
				ctx.stroke();
		};
		
		this.constructor = function(conf){
			if (!conf)
				return this;
			if (!conf.drawType)
				this.setDrawType(conf.drawType);
			if (conf.pos != null && (conf.pos.x != null || conf.pos.y != null))
				this.setPos(conf.pos);
			if (conf.dots != null && typeof conf.dots == "object" && conf.dots.length != null && conf.dots.length > 0){
				var length = conf.dots.length;
				for(var i = 0 ; i < length ; i++){
					this.dots.push(new Clg.Dot(conf.dots[i]));	
				}
			}
			return this;
		};
		
		return this.constructor(conf);
	};
	
	
	/**
	* @class Line
	*/
	Clg.Line = function(conf){
		this.extend = new Array(Clg.Shape);
		
		this.getB = function(){
			return this.dots[0];
		};
						
		this.setB = function(newB){
			this.dots[0].setXY(newB);
		};
		
		this.getDistance = function(){
			return  {
						x: this.getB().x-this.getA().x,
						y: this.getB().y-this.getA().y
					};	
		};
		
		this.constructor = function(conf){
			Clg.Utils.extend(this,this.extend,conf);
			if (!conf)
				return this;
			if (conf.dots[0] != null )
				this.setB(new Clg.Dot(conf.dots[0]));
			else
				this.setB(new Clg.Dot({x:5,y:5}));
			return this;
		};
		
		return this.constructor(conf);
	};
	
	/**
	* @class Rectangle
	*/
	Clg.Rectangle = function(conf){
		this.extend = new Array(Clg.Shape);
		
		this.width = 200;
		this.height = 100;
		
		this.getWidth = function(){
			return this.width;	
		};
		
		this.setWidth = function(newWidth){
			this.width = newWidth;	
			this.updateDots();
		};
		
		this.getHeight = function(){
			return this.height;	
		};
		
		this.setHeight = function(newHeight){
			this.height = newHeight;	
			this.updateDots();
		};
		
		this.updateDots = function(){
			for(var i = 0;i<3;i++){
				this.dots[i].setXY({x: (i<2) ? this.pos.getX()+this.width : this.pos.getX() ,y: (i<3&&i>0) ? this.height+this.pos.getY() : this.pos.getY() });
			}
			
		};
		
		this.constructor = function(conf){
			Clg.Utils.extend(this,this.extend,conf);
			
			for(var i = 0;i<3;i++){
				this.dots.push(new Clg.Dot());
			}
			if (!conf)
				return this;
			if (conf.width != null && Clg.Utils.isNumber(conf.width))
				this.setWidth(conf.width);
			if (conf.height != null && Clg.Utils.isNumber(conf.height))
				this.setHeight(conf.height);
			
			this.updateDots();
			return this;
		};
		
		return this.constructor(conf);
	};
	
	/**
	* @class Square
	*/
	Clg.Square = function(conf){
		this.extend = new Array(Clg.Rectangle);
				
		this.setWidth = function(newWidth){
			this.width = newWidth;
			this.setHeight(newWidth);
			this.updateDots();
		};
		
		this.setHeight = function(newHeight){
			this.height = newHeight;
			this.setWidth(newHeight);
			this.updateDots();
		};
		
		this.constructor = function(conf){
			Clg.Utils.extend(this,this.extend,conf);
			
			if (!conf)
				return this;
			if (conf.width != null && Clg.Utils.isNumber(conf.width)){
				this.setWidth(conf.width);
				this.setHeight(conf.width);
				this.updateDots();
			}
			
			return this;
		};
		
		return this.constructor(conf);
	};
	
	Clg.Arc = function(conf){
		this.extend = new Array(Clg.Shape);
	
			//a changer pour finir
		this.draw = function(ctx){
			ctx.beginPath();
			//ctx.moveTo(this.getPos().getX(),this.getPos().getY());
			
			ctx.arc(50,
					50,
					20,
					0,
					Math.PI+(Math.PI*j)/2,true);
			ctx.closePath();
			if (this.getDrawType() == "fill")
				ctx.fill();
			else 
				ctx.stroke();
		};
	
		this.constructor = function(conf){
			Clg.Utils.extend(this,this.extend,conf);
			if (!conf)
				return this;
			return this;
		};
		
		return this.constructor(conf);;
	};
	
	
	/**
	* @class Game
	*/
	Clg.Game = function(conf){
		this.running = false;
		this.entities = new Array();
		this.canvas = null;
		this.ctx = null;
		this.idCanvas = null;
		this.showFps = false;
		
		this.addEntity = function(newEntity){
			this.entities.push(newEntity);	
		};
		
		this.delAllEntities = function(){
			this.entities = new Array();	
		};
		
		this.drawEntities = function(){
			var length = this.entities.length;
			for(var i = 0;i<length;i++){
				this.entities[i].draw(this.ctx);
			}
		};
		
		this.getScreenWidth = function(){
			return this.canvas.width;
		};
		
		this.getScreenHeight = function(){
			return this.canvas.height;
		};
		
		this.Launch = function(){
			var tmpDate = new Date().getMilliseconds();
			this.clearScreen();
			this.drawEntities();
			var timeLapse = this.displayFps(tmpDate);
			setTimeout(function(el){el.Launch();},1-timeLapse > 0 ? 1-timeLapse : 0,this);
		};
		
		this.clearScreen = function(){
			this.ctx.clearRect(0,0,this.canvas.width,this.canvas.height);
		};
		
		this.displayFps = function(tmpDate){
			if (!this.showFps)
				return (new Date().getMilliseconds() - tmpDate);
			this.ctx.save();
			this.ctx.font = "18px sans-serif";
			var timeLapse = (new Date().getMilliseconds()) - tmpDate;
			timeLapse = timeLapse > 0 ? timeLapse : 1;
			var fps = Math.round(1000/timeLapse);
			this.ctx.fillStyle = fps > 60 ? "green" : (fps > 25 ? "orange" : "red");
			this.ctx.fillText("Fps : "+fps,this.canvas.width-88,18);
			this.ctx.restore();
			return timeLapse;
		};
		
		this.init = function(){
			this.canvas = document.getElementById('caliga');
			if (this.canvas.getContext){
				this.ctx = this.canvas.getContext('2d');
			}
		};
		
		this.constructor = function(conf){
			if (!conf)
				return this;
			if (typeof conf.idCanvas === "string")
				this.idCanvas = conf.idCanvas;
			if (typeof conf.showFps === "boolean")
				this.showFps = conf.showFps;
			this.init();
			return this;
		};
		
		return this.constructor(conf);
	};
})();